This notebook deals with a realistic model of the aircraft at take-off conditions. We deal with transport-type airplanes and write the general take-off equations. There are several different types of aircraft take-off. We will refer exclusively to Conventional Take-Off.
We consider a take-off operation on a vertical plane. Due to the level of approximations that it is possible to achieve, in the calculation of the take-off of a conventional airplane, we will assume that the runway reference system and the ground reference system are equivalent.
The sequence of airplane speeds during take-off are given in the figure below.
The airplane accelerates, the nose landing gear lifts off and the airplane rotates with a speed $V_R$; the airplane lifts off the ground with a speed $V_{LOF}$ and follows a rectilinear flight path to clear a conventional screen at 35 feet from the ground.
The take-off is divided into three segments:
The ground run is the distance between brake-release and lift-off of the forward wheels. To calculate the ground run, we write the dynamics equations on the centre of gravity of the aircraft in the horizontal and vertical directions, for a take-off from a horizontal runway. The engine thrust is aligned with the vector velocity.
Governing equations:
State Increments:
The thrust is given by the thrust model which takes as an input the speed.
Target: Reach $V_R$
The lift-off point is reached with at least one landing gear on the ground. The rotation of the aircraft must be done with a small angle or else there is a risk of a tail strike on the runway. The rotation run is the distance between lift-off of the forward wheels and lift-off of the main landing gears.
Governing equations:
Constant: $q = Rotation Rate$
State Increments:
Target : $W = L(\alpha)$
In this segment we will try to compute the state of the aircraft from $V_{LOF}$ up to point A.
Governing equations:
Target: Reach 35ft
The climb velocity in general accelerated flight is
$v_c = \frac{T-D}{W}U - \frac{U}{g}dU/dt$
In our case we want to climb with a max rate of climb, thus our target is to minimize the accelaration. The pilot can control the acceleration of the a/c with the stick input, thus the change of $\alpha$. The easiest way to model this procedure is to create a simple gain control loop.
A simple schema of the control function is illustrated below:
# Post Processing
import pandas as pd
import numpy as np
# Plotting
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# Take Off Segments
from src.modules.take_off_env import TakeOffPrep
from src.modules.ground_phase import GroundRoll
from src.modules.rotation_phase import RotationPhase
from src.modules.airborne_phase import AirbornePhase
input_variables = {
"mass": 80e3, # [kg]
"conf": "1+F",
"zp": 0, # [ft]
"lg": "Up",
"engine_state": "OEI",
"timestep": 1e-1,
}
Before initiating the TakeOff Procedure some preliminary steps have to be made first.
A dedicated class was created to prepare the take-off
example_preperation = TakeOffPrep(input_variables)
We calculate the stall speed with the following equation: $ V_{stall} = \sqrt(\frac{2 * mg}{(\rho S C_{Lmax}}) $
example_preperation.calculate_stall_speed()
print(f"Stall Speed = {round(example_preperation.v_sta, 2)}kt")
Stall Speed = 129.71kt
example_preperation.define_characteristic_speeds()
print("Characteristic Speeds\n")
for key, value in example_preperation.speeds.items():
print (f"{key} = {round(float(value), 2)}kt")
Characteristic Speeds v2min = 152.22kt vr = 136.2kt vef = 134.2kt vmca = 114.6kt v_stall = 129.71kt
In the case of non compliance of $V_{2min}$ with JAR25.121b, we take the ssg of JAR(2.4%) and we calculate the new $V_2$
example_preperation.calculate_v2_jar()
JAR Assertion: SSG of V2min 4.7% Passed
All these methods are summed up into one function in the same class called pilot_preparation.
Now that we have our characteristic speeds, we can start our take off procedure. The idea here is that we start with the minimum $V_R$ and we try to reach $V_2$ until we reach 35ft.
If at any point of the flight the corresponding speed does not pass the criteria then we incrementally increase the $V_R$ by $1\% V_{stall}$ and we start the iterative process again until all the criteria are met.
class TakeOffProc(GroundRoll, RotationPhase, AirbornePhase):
def check_vr(self) -> None:
if self.variables["need_to_increase_Vr"]:
self.speeds["vr"] += 0.01 * self.speeds["v_stall"]
self.speeds["vef"] = self.speeds["vr"] - 2
print(f"VR increased at {self.speeds['vr']} kt")
super().initialize_data()
def takeoff(self) -> None:
super().pilot_preparation() # calculate all the characteristic speeds
print(f"Vr = {self.speeds['vr']} kt")
while self.variables["cas_kt"] < self.speeds["v_target"]:
super().up_to_rotation() # 1st segment of takeoff
super().transition_phase() # 2nd segment of takeoff
self.check_vr()
if not self.variables["need_to_increase_Vr"]:
super().airborne_phase() # 3rd segment of takeoff
self.check_vr()
The above class inherits the 3 takeoff segments, which correspondingly inherit the take-off preparation class. In case that the $V_R$ does not pass the take-off critera, we then increase it incrementally by 1% of the stall speed until all the criteria pass.
amazing_aircraft = TakeOffProc(input_variables)
amazing_aircraft.takeoff()
JAR Assertion: SSG of V2min 4.7% Passed Vr = 136.20010905033593 kt Could not reach V2 Increase VR the a/c cannot reach the target :( VR increased at 137.4972529460534 kt Could not reach V2 Increase VR the a/c cannot reach the target :( VR increased at 138.7943968417709 kt Could not reach V2 Increase VR the a/c cannot reach the target :( VR increased at 140.09154073748837 kt Could not reach V2 Increase VR the a/c cannot reach the target :( VR increased at 141.38868463320586 kt Could not reach V2 Increase VR the a/c cannot reach the target :( VR increased at 142.68582852892334 kt Could not reach V2 Increase VR the a/c cannot reach the target :( VR increased at 143.98297242464082 kt Could not reach V2 Increase VR the a/c cannot reach the target :( VR increased at 145.2801163203583 kt V2min reached @ 0.18ft!
So, the algorithm finally converged to a specific $V_R$!
In order to post process the results we are going to transform the log dictionary to a pandas dataframe.
df = pd.DataFrame(amazing_aircraft.event_log)
df["accel_cas"] = np.gradient(df["cas_kt_log"], df["t_log"], edge_order=2)
df["accel_tas"] = np.gradient(df["tas_kt_log"], df["t_log"], edge_order=2)
display(df.tail(50))
| t_log | x_log | height_log | cas_kt_log | tas_kt_log | vz_log | teta_log | alpha_log | gamma_log | thrust_log | lift_log | drag_log | accel_cas | accel_tas | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 340 | 34.0 | 1423.667079 | 0.000000 | 151.845921 | 151.845921 | 0.000000 | 12.200000 | 12.200000 | 0.000000 | 104606.470312 | 762779.300608 | 64742.875097 | 0.882056 | 0.882056 |
| 341 | 34.1 | 1431.480928 | 0.000000 | 151.931529 | 151.931529 | 0.000000 | 12.500000 | 12.500000 | 0.000000 | 104606.470312 | 777337.380966 | 66851.161006 | 0.824255 | 0.824255 |
| 342 | 34.2 | 1439.299017 | 0.000000 | 152.010772 | 152.010772 | 0.000000 | 12.800000 | 12.800000 | 0.000000 | 104606.470312 | 791874.500481 | 69349.890072 | 0.746277 | 0.746402 |
| 343 | 34.3 | 1447.119144 | 0.011222 | 152.080785 | 152.080810 | 0.039054 | 13.236276 | 13.207662 | 0.028614 | 104606.470312 | 809946.060153 | 72633.586554 | 0.653400 | 0.653850 |
| 344 | 34.4 | 1454.942868 | 0.040393 | 152.141452 | 152.141542 | 0.101515 | 13.642181 | 13.567838 | 0.074343 | 104606.470312 | 827101.898675 | 75701.093454 | 0.557485 | 0.558405 |
| 345 | 34.5 | 1462.769702 | 0.093881 | 152.192282 | 152.192491 | 0.186136 | 14.016199 | 13.879940 | 0.136259 | 104606.470312 | 841263.927558 | 78767.126302 | 0.463172 | 0.464692 |
| 346 | 34.6 | 1470.599124 | 0.176944 | 152.234087 | 152.234481 | 0.289062 | 14.352964 | 14.141429 | 0.211535 | 104606.470312 | 852960.179685 | 81334.840063 | 0.376894 | 0.379122 |
| 347 | 34.7 | 1478.430655 | 0.293928 | 152.267660 | 152.268315 | 0.407104 | 14.654330 | 14.356494 | 0.297836 | 104606.470312 | 862461.256660 | 83444.139965 | 0.298145 | 0.301169 |
| 348 | 34.8 | 1486.263848 | 0.448360 | 152.293716 | 152.294715 | 0.537421 | 14.922302 | 14.529212 | 0.393090 | 104606.470312 | 870098.880250 | 85155.521479 | 0.227196 | 0.231087 |
| 349 | 34.9 | 1494.098290 | 0.643070 | 152.313100 | 152.314533 | 0.677591 | 15.158784 | 14.663252 | 0.495532 | 104606.470312 | 876030.609986 | 86436.851415 | 0.164880 | 0.169693 |
| 350 | 35.0 | 1501.933610 | 0.880254 | 152.326692 | 152.328653 | 0.825402 | 15.366525 | 14.762972 | 0.603553 | 104606.470312 | 880446.062422 | 87295.227152 | 0.109521 | 0.115300 |
| 351 | 35.1 | 1509.769479 | 1.161545 | 152.335004 | 152.337593 | 0.978890 | 15.548622 | 14.832896 | 0.715726 | 104606.470312 | 883543.491806 | 87899.762019 | 0.059232 | 0.066007 |
| 352 | 35.2 | 1517.605596 | 1.488080 | 152.338538 | 152.341855 | 1.136342 | 15.706465 | 14.875657 | 0.830808 | 104606.470312 | 885438.232609 | 88270.533903 | 0.013882 | 0.021673 |
| 353 | 35.3 | 1525.441684 | 1.860551 | 152.337780 | 152.341927 | 1.296199 | 15.841505 | 14.893838 | 0.947667 | 104606.470312 | 886243.956573 | 88428.424686 | -0.026705 | -0.017888 |
| 354 | 35.4 | 1533.277494 | 2.279243 | 152.333197 | 152.338277 | 1.457049 | 15.955219 | 14.889941 | 1.065278 | 104606.470312 | 886071.211913 | 88394.562076 | -0.062746 | -0.052900 |
| 355 | 35.5 | 1541.112800 | 2.744078 | 152.325231 | 152.331347 | 1.617625 | 16.049084 | 14.866362 | 1.182722 | 104606.470312 | 885026.325063 | 88189.866952 | -0.094478 | -0.083611 |
| 356 | 35.6 | 1548.947405 | 3.254652 | 152.314301 | 152.321555 | 1.776798 | 16.124562 | 14.825382 | 1.299180 | 104606.470312 | 883210.613763 | 87834.698297 | -0.122158 | -0.110281 |
| 357 | 35.7 | 1556.781135 | 3.810277 | 152.300800 | 152.309291 | 1.933574 | 16.183080 | 14.769154 | 1.413926 | 104606.470312 | 880719.860945 | 87348.585219 | -0.146045 | -0.133177 |
| 358 | 35.8 | 1564.613840 | 4.410013 | 152.285092 | 152.294920 | 2.087081 | 16.226022 | 14.699695 | 1.526327 | 104606.470312 | 877644.002003 | 86750.034363 | -0.166327 | -0.152492 |
| 359 | 35.9 | 1572.445393 | 5.052705 | 152.267534 | 152.278793 | 2.236567 | 16.254722 | 14.618890 | 1.635832 | 104606.470312 | 874066.982556 | 86050.207911 | -0.181777 | -0.167005 |
| 360 | 36.0 | 1580.275689 | 5.737012 | 152.248737 | 152.261519 | 2.381388 | 16.270534 | 14.528563 | 1.741971 | 104606.470312 | 870070.173685 | 85149.060724 | -0.192796 | -0.177118 |
| 361 | 36.1 | 1588.104658 | 6.461441 | 152.228975 | 152.243369 | 2.521014 | 16.276210 | 14.431861 | 1.844350 | 104606.470312 | 865793.221769 | 84189.011016 | -0.201213 | -0.184663 |
| 362 | 36.2 | 1595.932250 | 7.224397 | 152.208494 | 152.224586 | 2.655088 | 16.272902 | 14.330197 | 1.942705 | 104606.470312 | 861299.001676 | 83184.940177 | -0.207307 | -0.189922 |
| 363 | 36.3 | 1603.758429 | 8.024207 | 152.187514 | 152.205385 | 2.783337 | 16.261668 | 14.224835 | 2.036834 | 104606.470312 | 856643.670970 | 82150.010335 | -0.211332 | -0.193151 |
| 364 | 36.4 | 1611.583176 | 8.859136 | 152.166228 | 152.185956 | 2.905556 | 16.243482 | 14.116901 | 2.126582 | 104606.470312 | 851877.223413 | 81095.796416 | -0.213523 | -0.194584 |
| 365 | 36.5 | 1619.406483 | 9.727415 | 152.144809 | 152.166468 | 3.021608 | 16.219241 | 14.007397 | 2.211844 | 104606.470312 | 847044.016751 | 80032.419411 | -0.213722 | -0.194067 |
| 366 | 36.6 | 1627.228355 | 10.627246 | 152.123484 | 152.147143 | 3.131412 | 16.189767 | 13.897209 | 2.292558 | 104606.470312 | 842048.208140 | 78938.339050 | -0.212129 | -0.191797 |
| 367 | 36.7 | 1635.048811 | 11.556778 | 152.102383 | 152.128108 | 3.234771 | 16.156072 | 13.787500 | 2.368572 | 104606.470312 | 837067.101407 | 77853.444913 | -0.209323 | -0.188355 |
| 368 | 36.8 | 1642.867880 | 12.514165 | 152.081619 | 152.109471 | 3.331709 | 16.118851 | 13.678951 | 2.439900 | 104606.470312 | 832141.334900 | 76786.526957 | -0.205491 | -0.183929 |
| 369 | 36.9 | 1650.685599 | 13.497585 | 152.061285 | 152.091323 | 3.422302 | 16.078722 | 13.572129 | 2.506592 | 104606.470312 | 827296.508227 | 75742.890480 | -0.202096 | -0.179979 |
| 370 | 37.0 | 1658.502008 | 14.505245 | 152.041200 | 152.073476 | 3.506657 | 16.036247 | 13.467523 | 2.568724 | 104606.470312 | 822554.633794 | 74835.397854 | -0.199587 | -0.176954 |
| 371 | 37.1 | 1666.317144 | 15.535390 | 152.021368 | 152.055932 | 3.584902 | 15.990583 | 13.364194 | 2.626389 | 104606.470312 | 817873.086796 | 73986.072531 | -0.196518 | -0.173410 |
| 372 | 37.2 | 1674.131042 | 16.586284 | 152.001896 | 152.038794 | 3.657113 | 15.941810 | 13.262170 | 2.679641 | 104606.470312 | 813252.965892 | 73152.328193 | -0.192446 | -0.168899 |
| 373 | 37.3 | 1681.943744 | 17.656219 | 151.982879 | 152.022152 | 3.723375 | 15.890534 | 13.161998 | 2.728536 | 104606.470312 | 808719.032276 | 72338.425508 | -0.187493 | -0.163546 |
| 374 | 37.4 | 1689.755298 | 18.743518 | 151.964397 | 152.006084 | 3.783799 | 15.837318 | 13.064164 | 2.773154 | 104606.470312 | 804293.030710 | 71547.998515 | -0.181613 | -0.157302 |
| 375 | 37.5 | 1697.565758 | 19.846544 | 151.946556 | 151.990692 | 3.838529 | 15.782683 | 12.969088 | 2.813595 | 104606.470312 | 799919.907899 | 70770.685183 | -0.174600 | -0.149961 |
| 376 | 37.6 | 1705.375182 | 20.963681 | 151.929477 | 151.976092 | 3.887638 | 15.727214 | 12.877304 | 2.849910 | 104606.470312 | 795551.914480 | 69997.635966 | -0.166762 | -0.141830 |
| 377 | 37.7 | 1713.183636 | 22.093320 | 151.913204 | 151.962325 | 3.931143 | 15.671550 | 12.789444 | 2.882106 | 104606.470312 | 791372.503785 | 69261.680531 | -0.158547 | -0.133356 |
| 378 | 37.8 | 1720.991189 | 23.233920 | 151.897768 | 151.949421 | 3.969288 | 15.616084 | 12.705724 | 2.910360 | 104606.470312 | 787391.770148 | 68564.093525 | -0.150041 | -0.124626 |
| 379 | 37.9 | 1728.797907 | 24.384015 | 151.883195 | 151.937400 | 4.002330 | 15.561174 | 12.626317 | 2.934857 | 104606.470312 | 783617.578222 | 67905.751308 | -0.141327 | -0.115718 |
| 380 | 38.0 | 1736.603862 | 25.542215 | 151.869503 | 151.926277 | 4.030535 | 15.507139 | 12.551348 | 2.955791 | 104606.470312 | 780055.739441 | 67287.175104 | -0.132879 | -0.107105 |
| 381 | 38.1 | 1744.409121 | 26.707208 | 151.856619 | 151.915979 | 4.054176 | 15.454268 | 12.480906 | 2.973362 | 104606.470312 | 776710.177273 | 66741.568295 | -0.125288 | -0.099377 |
| 382 | 38.2 | 1752.213749 | 27.877762 | 151.844445 | 151.906402 | 4.073528 | 15.402400 | 12.414630 | 2.987771 | 104606.470312 | 773563.502673 | 66278.947450 | -0.118056 | -0.092035 |
| 383 | 38.3 | 1760.017803 | 29.052717 | 151.833008 | 151.897572 | 4.088844 | 15.351203 | 12.351999 | 2.999204 | 104606.470312 | 770590.879831 | 65843.530409 | -0.110570 | -0.084464 |
| 384 | 38.4 | 1767.821342 | 30.230977 | 151.822331 | 151.889509 | 4.100347 | 15.300987 | 12.293163 | 3.007824 | 104606.470312 | 767799.221613 | 65436.049565 | -0.102902 | -0.076734 |
| 385 | 38.5 | 1775.624424 | 31.411515 | 151.812428 | 151.882225 | 4.108271 | 15.252036 | 12.238234 | 3.013802 | 104606.470312 | 765193.661979 | 65056.981944 | -0.095118 | -0.068910 |
| 386 | 38.6 | 1783.427107 | 32.593370 | 151.803307 | 151.875727 | 4.112855 | 15.204601 | 12.187288 | 3.017313 | 104606.470312 | 762777.665006 | 64706.571138 | -0.087280 | -0.061052 |
| 387 | 38.7 | 1791.229447 | 33.775652 | 151.794972 | 151.870015 | 4.114342 | 15.158903 | 12.140368 | 3.018534 | 104606.470312 | 760553.133590 | 64384.848052 | -0.079446 | -0.053216 |
| 388 | 38.8 | 1799.031500 | 34.957543 | 151.787418 | 151.865084 | 4.112980 | 15.115134 | 12.097487 | 3.017648 | 104606.470312 | 758520.517258 | 64091.650459 | -0.071670 | -0.045455 |
| 389 | 38.9 | 1806.833320 | 36.138294 | 151.780638 | 151.860924 | 4.109014 | 15.073460 | 12.058627 | 3.014833 | 104606.470312 | 756678.919064 | 63826.641429 | -0.063935 | -0.037743 |
Now we are going to check the time and speed values that the algorithm found about the characteristic speeds.
pd.DataFrame(amazing_aircraft.characteristic_instants)
| Rotation | LiftOff | v35ft | v2 | |
|---|---|---|---|---|
| Instant | 30.00 | 34.20 | 38.90 | 34.60 |
| Speed | 145.39 | 152.01 | 151.78 | 152.23 |
We can see that the rotation started 30 seconds after the break release.
Then 4 seconds later the aircraft lifts off!
Almost 9 seconds after the aircraft rotation is already at 35ft!
We can see that $V_{LOF}$ is very close to $V_2$, this makes sense since we want to use most of the a/c energy to climb meaning that we should expect to see a pretty steep curve of $V_z(t)$
Remark: We can see that there is a difference between the values $(V_2, V_{35ft}) $. This is due to the effect of the controller. The acceleration is never 0 but oscillates around this value. Thus with non zero acceleration we can expect to have small differences in the values of speed at the airborne phase.
pd.DataFrame(amazing_aircraft.speeds)
| v2min | vr | vef | vmca | v_stall | v_target | |
|---|---|---|---|---|---|---|
| 0 | 152.221103 | 145.280116 | 143.280116 | 114.5999 | 129.71439 | 152.221103 |
Remark: The $V_R$ is not exactly the same with the above results due to the sensitivity of the timestep. If we reduce the timestep then the increments dx and dv should tend to be continuous thus, reach this value
fig = px.line(df, x='t_log', y= "x_log")
# Edit the layout
fig.update_layout(title='Distance in function of time',
xaxis_title='Time[s]',
yaxis_title='Distance x_ground-axis[m]')
fig.show()
The above curve has the expected shape, since in the ground segment the a/c follows an non-constant accelerating motion and then for the airborne phase should be more or less linear since we try to have zero acceleration.
In fact we can see that up to 34 seconds the curve follows a concave up shape and then it tends to become linear.
fig = px.line(df, x='t_log', y= "tas_kt_log")
fig.update_layout(title='True Air Speed in function of time',
xaxis_title='Time [s]',
yaxis_title='TAS [kt]')
fig.show()
In the above graph we can see that the velocity is augmentating in a non linear manner up to 34.2 seconds, which makes perfect sense since the acceleration is not constant in the ground phase, and then tends to stabilize in the $V_2$ value, which again makes sense since the pilot is targeting zero acceleration in the airborne phase in order to climb as fast as possible.
fig = px.line(df, x='t_log', y= "vz_log")
fig.update_layout(title='Rate of Climb in function of time',
xaxis_title='Time [s]',
yaxis_title='Rate of Climb [m/s]')
fig.show()
As expected the rate of climb is 0 until lift-off(34.2 secs) and then we see a rapid increase due to the effort of max climb. The peak of this curve marks the peak of the climb gradient, since $V_z = TAS\sin\gamma$ and TAS is quasi static.
fig = px.line(df, x='t_log', y=["alpha_log", "teta_log", "gamma_log"])
fig.update_layout(title='Aoa, teta & gamma in function of time',
xaxis_title='Time[s]',
yaxis_title='Degrees')
fig.show()
In this graph we can see that until lift-off $\alpha$ and $\theta$ have the same value since $\gamma$ is 0. When the a/c is airborne and tries to climb the value of gamma goes up. $\gamma$ is approximately given by the following formula:
$\gamma = \frac{T\cos\alpha -D}{W}$
This formula makes evident that in order to increase $\gamma$ we have to lower $\alpha$. This happens due to two main reasons.
For $\alpha$ we see that it increases until it reaches the target acceleration and then starts to decrease.
$\theta$ is calculated by the known formula :
$\theta = \alpha + \gamma$
# Create figure with secondary y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])
# Add traces
fig.add_trace(
go.Scatter(x=df['t_log'], y=df["accel_tas"], name="Acceleration"),
secondary_y=False,
)
fig.add_trace(
go.Scatter(x=df['t_log'], y=df["alpha_log"], name="Angle of Attack"),
secondary_y=True,
)
# Add figure title
fig.update_layout(
title_text="Acceleration and Angle of Attack in function of time"
)
# Set x-axis title
fig.update_xaxes(title_text="Time[s]")
# Set y-axes titles
fig.update_yaxes(title_text="TASA [m/s2]", secondary_y=False)
fig.update_yaxes(title_text="Alpha [deg]", secondary_y=True)
fig.show()
As far as $\alpha$ is concerned, as stated in the definition of the airborne segment, is the tool that the pilot uses it in order to control the acceleration. When the a/c is airborne with a positive acceleration the pilot pull the stick in order to increase $\alpha$ and decrease the acceleration. We can see that at the peak of $\alpha$ the accleration is very close to zero. Then, the accelarion goes negative and the pilot pushes the stick, thus reducing $\alpha$ in order to control the acceleration close to the region of 0.
This notebook presents the AFM OEI Take Off procedure. The user has to input the initial a/c and atmosperic conditions and then the code is able to produce an analytical decription of the take off procedure. The results are satisfying and produce an accurate description of the take off procedure. Then the user can post process the information as he likes.
In this simulation there are several factors that were not taken into account:
These factors limit the accuracy of the model